/*
 * Copyright (c) 2017.  nbgold
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.vdong.redis.data.core;

import com.google.common.base.Optional;
import com.vdong.redis.data.core.json.FastJsonRedisTemplate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 *
 * @author <a href="mailto:yrh@qtz360.com">yrh</a>
 * @Date Create on 2018年07月27日
 * @since version1.0 Copyright 2018 QTZ All Rights Reserved.
 */
public abstract class AbstractRedisOperator implements RedisOperator {

    private final Logger log = LogManager.getLogger("exceptionLog");

    public Optional<String> get(String key) {
        try {
            return getImpl(key);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<String> getImpl(String key);

    public <T> Optional<T> get(String key, Class<T> clz) {
        try {
            return getImpl(key, clz);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract <T> Optional<T> getImpl(String key, Class<T> clz);

    public <E> Optional<List<E>> getForList(String key, Class<E> clz) {
        try {
            return getForListImpl(key, clz);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract <E> Optional<List<E>> getForListImpl(String key, Class<E> clz);


    public void set(String key, Object value) {
        try {
            setImpl(key, value);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void setImpl(String key, Object value);


    public void set(String key, Object value, long second) {
        try {
            setImpl(key, value, second);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void setImpl(String key, Object value, long second);


    public void set(String key, Object value, long timeout, TimeUnit unit) {
        try {
            setImpl(key, value, timeout, unit);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void setImpl(String key, Object value, long timeout, TimeUnit unit);


    public Optional<Boolean> setNx(String key, Object value) {
        try {
            return setNxImpl(key, value);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Boolean> setNxImpl(String key, Object value);


    public void setEx(String key, Object value, long seconds) {
        try {
            setExImpl(key, value, seconds);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void setExImpl(String key, Object value, long seconds);


    public void setEx(String key, Object value, long timeout, TimeUnit unit) {
        try {
            setExImpl(key, value, timeout, unit);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void setExImpl(String key, Object value, long timeout, TimeUnit unit);


    public Optional<Long> incr(String key) {
        try {
            return incrImpl(key);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Long> incrImpl(String key);


    public Optional<Long> incrBy(String key, long delta) {
        try {
            return incrByImpl(key, delta);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Long> incrByImpl(String key, long delta);


    public Optional<Long> decrBy(String key, long delta) {
        try {
            return decrByImpl(key, delta);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Long> decrByImpl(String key, long delta);


    public Optional<Boolean> expire(String key, long seconds) {
        try {
            return expireImpl(key, seconds);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Boolean> expireImpl(String key, long seconds);


    public Optional<Boolean> expire(String key, long timeout, TimeUnit unit) {
        try {
            return expireImpl(key, timeout, unit);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Boolean> expireImpl(String key, long timeout, TimeUnit unit);


    public Optional<Boolean> expireAt(String key, Date date) {
        try {
            return expireAtImpl(key, date);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Boolean> expireAtImpl(String key, Date date);


    public void del(String key) {
        try {
            delImpl(key);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void delImpl(String key);


    public void del(String... keys) {
        try {
            delImpl(keys);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void delImpl(String... keys);


    public Optional<Boolean> hasKey(String key) {
        try {
            return hasKeyImpl(key);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Boolean> hasKeyImpl(String key);


    public <T> Optional<T> hget(String key, Object field) {
        try {
            return hgetImpl(key, field);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract <T> Optional<T> hgetImpl(String key, Object field);


    public <T> Optional<T> hget(String key, Object field, Class<T> clz) {
        try {
            return hgetImpl(key, field, clz);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract <T> Optional<T> hgetImpl(String key, Object field, Class<T> clz);


    public <E> Optional<List<E>> hgetForList(String key, Object field, Class<E> clz) {
        try {
            return hgetForListImpl(key, field, clz);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract <E> Optional<List<E>> hgetForListImpl(String key, Object field, Class<E> clz);


    public void hset(String key, Object field, String value) {
        try {
            hsetImpl(key, field, value);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void hsetImpl(String key, Object field, String value);


    public void hset(String key, Object field, Object value) {
        try {
            hsetImpl(key, field, value);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void hsetImpl(String key, Object field, Object value);


    public void hmset(String key, Map<Object, Object> hashMap) {
        try {
            hmsetImpl(key, hashMap);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
        }
    }

    protected abstract void hmsetImpl(String key, Map<Object, Object> hashMap);


    public Optional<Long> hdel(String key, String field) {
        try {
            return hdelImpl(key, field);
        } catch (DataAccessException e) {
            log.error("Redis connection error!", e);
            return Optional.absent();
        }
    }

    protected abstract Optional<Long> hdelImpl(String key, String field);


    public RedisTemplate<String, Object> getTemplate() {
        return null;
    }


    public FastJsonRedisTemplate<String, Object> getFastJsonRedisTemplate() {
        return null;
    }


    public void ignoreRedisException() {
    }
}
